package yamltester

import (
	"gopkg.in/yaml.v3"
	"os"
	"time"
	"wtester/config"
	"wtester/pkg/parabase"
	"wtester/pkg/stagebase"
	"wtester/pkg/taskbase"
	"wtester/pkg/yamlbase"
)

/**
  @author: weicai
  @since: 2024/4/7
  @desc: yaml测试
**/

func ParseYaml(path string) error {
	content, err := os.ReadFile(path)
	if err != nil {
		config.Logger.Error(err.Error())
		return err
	}
	var data []yamlbase.StageBuild
	err = yaml.Unmarshal(content, &data)
	if err != nil {
		config.Logger.Error(err.Error())
		return err
	}
	var lastStage, firstStage *stagebase.Stage
	for _, s := range data {
		d, _ := time.ParseDuration(s.Duration)
		var stage = stagebase.Stage{Concurrency: s.Concurrency, SpawnRate: s.SpawnRate, Duration: d.Seconds()}
		stage.Actuator = make([]*stagebase.Actuator, 0)
		for _, s1 := range s.Scenarios {
			task := make([]taskbase.TaskInterface, len(s1.Requests))
			for j, t := range s1.Requests {
				hasRangeP := false
				parameters := make([]parabase.TaskParamInterface, len(t.Parameters))
				for k, p := range t.Parameters {
					_p, err := parabase.InitTaskParam(p.Name, p.Type, p.Kind, p.Start, p.End, p.Step, p.Values)
					if err != nil {
						config.Logger.Error(err.Error())
						return err
					}
					parameters[k] = _p
					if p.Kind == "range" {
						hasRangeP = true
					}
				}
				task[j] = taskbase.InitTask(t.Name, t.Weight, hasRangeP, parameters)
			}
			constant, between := float32(0), []float32{0.1, 0.1}
			if s1.Sleep != nil {
				switch len(s1.Sleep) {
				case 0:
					constant = 0.1
				case 1:
					constant = s1.Sleep[0]
				default:
					if s1.Sleep[0] == s1.Sleep[1] {
						constant = s1.Sleep[0]
					} else {
						if s1.Sleep[0] > s1.Sleep[1] {
							s1.Sleep[0], s1.Sleep[1] = s1.Sleep[1], s1.Sleep[0]
						}
						between[0], between[1] = s1.Sleep[0], s1.Sleep[1]
					}
				}
			}
			a := stagebase.InitActuator(s1.Name, s1.IsSequential, s1.IsMaster, s1.Loops, s1.FixConcurrency, s1.Weight, constant, between, task)
			stage.Actuator = append(stage.Actuator, a)
		}
		if lastStage != nil {
			lastStage.NextStage = &stage
		} else {
			lastStage = &stage
			firstStage = &stage
		}
	}
	firstStage.Run(nil)
	return nil
}
